package com.example.alioss.controller;

import com.aliyun.oss.ClientException;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.OSSException;
import com.aliyun.oss.model.OSSObjectSummary;
import com.aliyun.oss.model.ObjectListing;
import com.aliyun.oss.model.PutObjectRequest;
import com.aliyun.oss.model.PutObjectResult;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.util.*;

/**
 * 实现文件上传的控制器
 */
@Controller
@RequestMapping("/upload")
public class UploadController {

    @Value("${uploadFolder}")
    private String fileDir;

    @RequestMapping("/html")
    public String picUpload(Map<String, Object> map) {//跳转到 upload.html
        ArrayList<String> list = getDirImages();
        map.put("hello", "阿里oss文件上传");
        map.put("list", list);
        return "uploadPage";
    }

    @RequestMapping("/uploadFile")
    public String upload(MultipartFile fileUpload, HashMap<String, Object> map) {
//        map.put("md5","123123");
//        map.put("path","https://bucket-zyj001.oss-cn-wulanchabu.aliyuncs.com/workplace/63c114f7-7f48-4189-9f9b-e18055fdcde8.png");
//        return "verifyPage";
        if (fileUpload == null) return "verifyPage";
        //获取文件名
        String fileName = fileUpload.getOriginalFilename();
        //获取文件后缀名
        String suffixName = fileName.substring(fileName.lastIndexOf("."));
        //重新生成文件名
        fileName = UUID.randomUUID() + suffixName;
        String upload_file_path = fileDir + fileName;
        //指定本地文件夹存储图片
        try {
            System.out.println("upload_file_path------->>" + upload_file_path);
            File dir = new File(fileDir);
            if (!dir.exists()) {
                dir.mkdirs();
            }
            File upload_file = new File(upload_file_path);
            fileUpload.transferTo(upload_file);
            HashMap<String, Object> data = uploadAliOss(upload_file_path, fileName, map);
//            return new Message(0, "success to upload", data.get("md5"), data.get("filePath"));
            return "verifyPage";
        } catch (Exception e) {
            e.printStackTrace();
//            return new Message(-1, e.getMessage(), null, null);
            return "verifyPage";
        }
    }

    /**
     * 第二种
     * PutObject-简单上传：https://help.aliyun.com/document_detail/84781.html
     * OSS MD5一致性校验说明：https://blog.csdn.net/Du_niu/article/details/126871719
     */
    /**
     * 其他参考：
     * oss简单上传：https://help.aliyun.com/document_detail/84781.html
     * oss如何获取单个或多个文件的URL？：https://help.aliyun.com/document_detail/39607.html
     */
    private HashMap<String, Object> uploadAliOss(String filePath, String fileName, HashMap<String, Object> values) throws Exception {
        // Endpoint以华东1（杭州）为例，其它Region请按实际情况填写。
        String endpoint = "https://oss-cn-wulanchabu.aliyuncs.com";
        String bucketEndPoint = "https://bucket-zyj001.oss-cn-wulanchabu.aliyuncs.com/";
        // 阿里云账号AccessKey拥有所有API的访问权限，风险很高。强烈建议您创建并使用RAM用户进行API访问或日常运维，请登录RAM控制台创建RAM用户。
        String accessKeyId = "LTAI5t9oZARsZ2adunwQTb9C";
        String accessKeySecret = "clC3svU2HQqzSZXVB4Le4Zzeo8szGw";
        // 填写Bucket名称，例如examplebucket。
        String bucketName = "bucket-zyj001";
        // 填写Object完整路径，完整路径中不能包含Bucket名称，例如exampledir/exampleobject.txt。
        String objectName = "workplace/" + fileName;
        // 填写本地文件的完整路径，例如D:\\localpath\\examplefile.txt。
        // 如果未指定本地路径，则默认从示例程序所属项目对应本地路径中上传文件。
//        String filePath = "D:\\localpath\\examplefile.txt";

        // 创建OSSClient实例。
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);

        try {
            // 创建PutObjectRequest对象。
            PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, objectName, new File(filePath));
            // 如果需要上传时设置存储类型和访问权限，请参考以下示例代码。
            // ObjectMetadata metadata = new ObjectMetadata();
            // metadata.setHeader(OSSHeaders.OSS_STORAGE_CLASS, StorageClass.Standard.toString());
            // metadata.setObjectAcl(CannedAccessControlList.Private);
            // putObjectRequest.setMetadata(metadata);

            // 设置该属性可以返回response。如果不设置，则返回的response为空。
            putObjectRequest.setProcess("true");

            // 上传文件。
            PutObjectResult result = ossClient.putObject(putObjectRequest);
            System.out.println("uploadAliOss-tag：" + result.getETag());
            // 如果上传成功，则返回200。
            System.out.println("uploadAliOss：" + result.getResponse().toString());
            System.out.println("uploadAliOss：" + result.getResponse().getUri());
            System.out.println("uploadAliOss：" + result.getResponse().getStatusCode());
            System.out.println("uploadAliOss：" + result.getResponse().getContentLength());
            System.out.println("uploadAliOss：" + result.getResponse().getErrorResponseAsString());
            values.put("status", 0);
            values.put("message", "success to upload");
            values.put("md5", result.getETag());
            values.put("filePath", bucketEndPoint + objectName);
            return values;
        } catch (OSSException oe) {
            System.out.println("Caught an OSSException, which means your request made it to OSS, "
                    + "but was rejected with an error response for some reason.");
            System.out.println("Error Message:" + oe.getErrorMessage());
            System.out.println("Error Code:" + oe.getErrorCode());
            System.out.println("Request ID:" + oe.getRequestId());
            System.out.println("Host ID:" + oe.getHostId());
            throw new Exception(oe.getErrorMessage());
        } catch (ClientException ce) {
            System.out.println("Caught an ClientException, which means the client encountered "
                    + "a serious internal problem while trying to communicate with OSS, "
                    + "such as not being able to access the network.");
            System.out.println("Error Message:" + ce.getMessage());
            throw new Exception(ce.getMessage());
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
    }

    private ArrayList<String> getDirImages() {
        // Endpoint以华东1（杭州）为例，其它Region请按实际情况填写。
        String endpoint = "https://oss-cn-wulanchabu.aliyuncs.com";
        String bucketEndPoint = "https://bucket-zyj001.oss-cn-wulanchabu.aliyuncs.com/";
        // 阿里云账号AccessKey拥有所有API的访问权限，风险很高。强烈建议您创建并使用RAM用户进行API访问或日常运维，请登录RAM控制台创建RAM用户。
        String accessKeyId = "LTAI5t9oZARsZ2adunwQTb9C";
        String accessKeySecret = "clC3svU2HQqzSZXVB4Le4Zzeo8szGw";
        // 填写Bucket名称，例如examplebucket。
        String bucketName = "bucket-zyj001";
        // 指定前缀，例如exampledir/object。
        String keyPrefix = "workplace/";

        // 创建OSSClient实例。
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);

        try {
            // 列举文件。如果不设置keyPrefix，则列举存储空间下的所有文件。如果设置keyPrefix，则列举包含指定前缀的文件。
            ObjectListing objectListing = ossClient.listObjects(bucketName, keyPrefix);
            List<OSSObjectSummary> sums = objectListing.getObjectSummaries();
            ArrayList<String> list = new ArrayList<>();
            for (OSSObjectSummary s : sums) {
                System.out.println("\t" + s.getKey());
                list.add(bucketEndPoint + s.getKey());
            }
            return list;
        } catch (OSSException oe) {
            System.out.println("Caught an OSSException, which means your request made it to OSS, "
                    + "but was rejected with an error response for some reason.");
            System.out.println("Error Message:" + oe.getErrorMessage());
            System.out.println("Error Code:" + oe.getErrorCode());
            System.out.println("Request ID:" + oe.getRequestId());
            System.out.println("Host ID:" + oe.getHostId());
        } catch (ClientException ce) {
            System.out.println("Caught an ClientException, which means the client encountered "
                    + "a serious internal problem while trying to communicate with OSS, "
                    + "such as not being able to access the network.");
            System.out.println("Error Message:" + ce.getMessage());
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
        return null;
    }
}
